/**
 * Author : Jorge Mejuto Create : 19/05/2009
 */

package net.eyra.negocio.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import net.eyra.negocio.entidades.explotacion.Division;
import net.eyra.negocio.entidades.explotacion.Lectura;
import net.eyra.negocio.entidades.explotacion.Parque;
import net.eyra.negocio.entidades.explotacion.Tarificador;
import net.eyra.negocio.entidades.explotacion.Zona;
import net.eyra.utiles.FormateoFechaException;
import net.eyra.utiles.Periodo;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

public class ExplotacionDao {

    public static int TIPO_TARIFICADOR_PRIMARIO = 1;
    public static int TIPO_TARIFICADOR_SECUNDARIO = 2;
    public static int TIPO_SUBESTACION = 3;

    public static int ZONA_GALICIA = 1;
    public static int ZONA_ANDALUCIA = 2;
    public static int ZONA_EXTREMADURA = 3;
    public static int ZONA_VALENCIA = 4;
    public static int ZONA_CATALUÑA = 5;
    public static int ZONA_LA_RIOJA = 6;
    public static int ZONA_CASTILLA_LA_MANCHA = 7;
    public static int ZONA_CASTILLA_LEON = 8;

    public List<Object[]> ResumenProduccionPorMesYAño(int id_tarificador) throws EyraDaoException {
        String sql = "SELECT periodo, sum(activa_exportada), sum(activa_importada), sum(reactiva_q1), sum(reactiva_q2), sum(reactiva_q3), sum(reactiva_q4) FROM lecturas_tm1 WHERE id_tarificador="
                + id_tarificador + " GROUP BY SUBSTRING_INDEX(periodo,'-',2) ORDER BY SUBSTRING_INDEX(periodo,'-',2)";
        Session session = null;
        List<Object[]> objetos = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            objetos = session.createSQLQuery(sql).list();
            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return objetos;
    }

    public List<Tarificador> ListaTarificadores(int tipo_tarificador, boolean activo) throws EyraDaoException {
        Session session = null;
        List<Tarificador> tarificadores = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            tarificadores = session.createCriteria(Tarificador.class)
                    .add(Restrictions.eq("orden", tipo_tarificador))
                    .add(Restrictions.eq("activo", activo ? "S" : "N"))
                    .addOrder(Order.asc("nombre"))
                    .list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return tarificadores;
    }

    public List<Parque> ListaParques(int tipo_tarificador, boolean activo) throws EyraDaoException {
        Session session = null;
        List<Parque> parques = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            parques = session.createCriteria(Parque.class)
                    .add(Restrictions.eq("activo", activo ? "S" : "N"))
                    .addOrder(Order.asc("nombre"))
                    .createCriteria("tarificadores")
                    .add(Restrictions.eq("orden", tipo_tarificador))
                    .list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return parques;
    }

    public List<Parque> ListaParquesZona(int tipo_tarificador, boolean activo, int zona) throws EyraDaoException {
        Session session = null;
        List<Parque> parques = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            parques = session.createCriteria(Parque.class)
                    .add(Restrictions.eq("activo", activo ? "S" : "N"))
                    .add(Restrictions.eq("zona.id_zona", zona))
                    .addOrder(Order.asc("nombre"))
                    .createCriteria("tarificadores")
                    .add(Restrictions.eq("orden", tipo_tarificador))
                    .add(Restrictions.eq("activo", activo ? "S" : "N"))
                    .list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return parques;
    }

    public List<Parque> ListaParquesDivision(int tipo_tarificador, boolean activo, int division) throws EyraDaoException {
        Session session = null;
        List<Parque> parques = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            parques = session.createCriteria(Parque.class)
                    .add(Restrictions.eq("activo", activo ? "S" : "N"))
                    .add(Restrictions.eq("division.id_division", division))
                    .addOrder(Order.asc("nombre"))
                    .createCriteria("tarificadores")
                    .add(Restrictions.eq("orden", tipo_tarificador))
                    .add(Restrictions.eq("activo", activo ? "S" : "N"))
                    .list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return parques;
    }

    /**
     * Recupera las cuartohorarias de una hora en concreto
     * 
     * @param id_tarificador
     * @param hora
     * @param periodo
     * @return
     * @throws FormateoFechaException
     * @throws EyraDaoException
     */
    public List<Lectura> RecuperarLecturas(int id_tarificador, int hora, String periodo) throws FormateoFechaException, EyraDaoException {
        Periodo _periodo = new Periodo();
        _periodo.setFecha_inicial(periodo, Periodo.FORMATO_FECHA_AAAA_MM_DD);

        Session session = null;
        List<Lectura> _lista = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            _lista = session.createCriteria("Lectura_tm2")
                    .add(Restrictions.eq("periodo", _periodo.getFecha_inicial()))
                    .add(Restrictions.eq("hora", hora))
                    .add(Restrictions.eq("tarificador.id_tarificador", id_tarificador))
                    .addOrder(Order.asc("fecha"))
                    .addOrder(Order.desc("verano"))
                    .list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return _lista;
    }

    /**
     * @param id_tarificador
     * @param periodo
     *            Ambas fecha inclusive
     * @param horaria
     *            'true': horaria, 'false': cuartohoraria
     * @return
     * @throws FormateoFechaException
     * @throws EyraDaoException
     */
    public List<Lectura> RecuperarLecturas(int id_tarificador, Periodo periodo, boolean horaria) throws FormateoFechaException, EyraDaoException {

        String lectura = horaria ? "Lectura_tm1" : "Lectura_tm2";

        Periodo _periodo = new Periodo(periodo);

        // TODO - El periodo tiene que venir ajustado. Aquí no hay nada que ajustar.
        _periodo.AjustarPeriodoCurvas(horaria ? Periodo.MEDIDA_TM1 : Periodo.MEDIDA_TM2);

        Session session = null;
        List<Lectura> _lista = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            _lista = session.createCriteria(lectura)
                    .add(Restrictions.between("fecha", _periodo.getFecha_inicial(), _periodo.getFecha_final()))
                    .add(Restrictions.eq("tarificador.id_tarificador", id_tarificador))
                    .addOrder(Order.asc("fecha"))
                    .addOrder(Order.desc("verano"))
                    .list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return _lista;
    }

    /**
     * @param id_tarificador
     * @param periodo
     *            Ambas fecha inclusive
     * @param horaria
     *            'true': horaria, 'false': cuartohoraria
     * @return
     * @throws FormateoFechaException
     * @throws EyraDaoException
     */
    public List<Lectura> RecuperarLecturasPorDia(int id_tarificador, Periodo periodo, boolean horaria) throws FormateoFechaException,
                                                                                                      EyraDaoException {

        String lectura = horaria ? "Lectura_tm1" : "Lectura_tm2";

        Periodo _periodo = new Periodo(periodo);
        // TODO - El periodo tiene que venir ajustado. Aquí no hay nada que ajustar.
        _periodo.AjustarPeriodoCurvas(horaria ? Periodo.MEDIDA_TM1 : Periodo.MEDIDA_TM2);

        Session session = null;
        List<Object[]> _lecturas = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            _lecturas = session.createCriteria(lectura)
                    .add(Restrictions.between("fecha", _periodo.getFecha_inicial(), _periodo.getFecha_final()))
                    .add(Restrictions.eq("tarificador.id_tarificador", id_tarificador))
                    .addOrder(Order.asc("fecha"))
                    .addOrder(Order.desc("verano"))
                    .setProjection(Projections.projectionList()
                                           .add(Projections.sum("activa_importada"))
                                           .add(Projections.sum("activa_exportada"))
                                           .add(Projections.sum("reactiva_q1"))
                                           .add(Projections.sum("reactiva_q2"))
                                           .add(Projections.sum("reactiva_q3"))
                                           .add(Projections.sum("reactiva_q4"))
                                           .add(Projections.groupProperty("periodo")))
                    .list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        List<Lectura> lecturas = new ArrayList<Lectura>();

        for (int x = 0; x < _lecturas.size(); x++) {
            Lectura _lectura = new Lectura();
            _lectura.setActiva_importada((_lecturas.get(x)[0] == null ? 0 : Double.parseDouble(_lecturas.get(x)[0].toString())));
            _lectura.setActiva_exportada((_lecturas.get(x)[1] == null ? 0 : Double.parseDouble(_lecturas.get(x)[1].toString())));
            _lectura.setReactiva_q1((_lecturas.get(x)[2] == null ? 0 : Double.parseDouble(_lecturas.get(x)[2].toString())));
            _lectura.setReactiva_q2((_lecturas.get(x)[3] == null ? 0 : Double.parseDouble(_lecturas.get(x)[3].toString())));
            _lectura.setReactiva_q3((_lecturas.get(x)[4] == null ? 0 : Double.parseDouble(_lecturas.get(x)[4].toString())));
            _lectura.setReactiva_q4((_lecturas.get(x)[5] == null ? 0 : Double.parseDouble(_lecturas.get(x)[5].toString())));
            _lectura.setPeriodo(_lecturas.get(x)[6] == null ? new Date() : (Date) _lecturas.get(x)[6]);
            lecturas.add(_lectura);
        }

        return lecturas;

    }

    public Lectura TotalProduccionPeriodo(int id_tarificador, Periodo periodo) throws FormateoFechaException, EyraDaoException {

        Session session = null;
        Object[] _lectura = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            _lectura = (Object[]) session.createCriteria("Lectura_tm1")
                    .add(Restrictions.eq("tarificador.id_tarificador", id_tarificador))
                    .add(Restrictions.between("fecha", periodo.getFecha_inicial(), periodo.getFecha_final()))
                    .setProjection(Projections.projectionList()
                                           .add(Projections.sum("activa_importada"))
                                           .add(Projections.sum("activa_exportada"))
                                           .add(Projections.sum("reactiva_q1"))
                                           .add(Projections.sum("reactiva_q2"))
                                           .add(Projections.sum("reactiva_q3"))
                                           .add(Projections.sum("reactiva_q4")))
                    .uniqueResult();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        Lectura lectura = new Lectura();

        if (_lectura != null && _lectura[0] != null) {
            lectura.setActiva_importada(Double.parseDouble(_lectura[0].toString()));
            lectura.setActiva_exportada(Double.parseDouble(_lectura[1].toString()));
            lectura.setReactiva_q1(Double.parseDouble(_lectura[2].toString()));
            lectura.setReactiva_q2(Double.parseDouble(_lectura[3].toString()));
            lectura.setReactiva_q3(Double.parseDouble(_lectura[4].toString()));
            lectura.setReactiva_q4(Double.parseDouble(_lectura[5].toString()));
        }
        return lectura;
    }

    /**
     * Devuelve una lista con las columnas 'id_tarificador' y 'MAX(fecha)' para la tabla seleccionada (TM1 o TM2)
     * 
     * @param horaria
     * @return
     * @throws EyraDaoException
     */
    public List<Object[]> RecuperarFechasUltimaActualizacion(boolean horaria) throws EyraDaoException {
        String sql = "SELECT id_tarificador, MAX(fecha) as fecha FROM " + (horaria ? "lecturas_tm1" : "lecturas_tm2")
                + " GROUP BY id_tarificador ORDER BY fecha ASC";
        Session session = null;
        List<Object[]> objetos = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            objetos = session.createSQLQuery(sql).list();
            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return objetos;
    }

    /**
     * Dado un tarificador devuelve una cadena que indica la última fecha de con lectura, horaria o cuartohoraria.
     * 
     * @param id_tarificador
     * @param horaria
     * @return
     * @throws EyraDaoException
     */
    public Date getUltimaFechaRegistradaPorTarificador(int id_tarificador, boolean horaria) throws EyraDaoException {

        String sql = "SELECT MAX(fecha) as fecha FROM " + (horaria ? "lecturas_tm1" : "lecturas_tm2") + " WHERE id_tarificador =" + id_tarificador;
        Session session = null;
        Date fecha = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            fecha = (Date) session.createSQLQuery(sql).uniqueResult();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return fecha;
    }

    /**
     * Carga los datos de fincas que pertenecen al parque y de acuerdos para el mismo
     * 
     * @param id_parque
     * @return
     * @throws EyraDaoException
     */
    public Parque getParque(int id_parque, boolean fincas) throws EyraDaoException {
        Session session = null;
        Parque parque = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            parque = (Parque) session.get(Parque.class, id_parque);
            if (fincas) {
                parque.getFincas().size();
                parque.getAcuerdos().size();
            }

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return parque;
    }

    /**
     * Listado de zonas en las que están distribuidos los parques
     * 
     * @return
     * @throws EyraDaoException
     */
    public List<Zona> ListaZonas() throws EyraDaoException {
        Session session = null;
        List<Zona> zonas = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            zonas = session.createCriteria(Zona.class).addOrder(Order.asc("nombre")).list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return zonas;
    }

    public Tarificador getTarificador(int id_tarificador) throws EyraDaoException {
        Session session = null;
        Tarificador tarificador = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            tarificador = (Tarificador) session.get(Tarificador.class, id_tarificador);

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return tarificador;
    }

    /**
     * Recupera las cuartohorarias de una hora en concreto
     * 
     * @param id_tarificador
     * @param hora
     * @param periodo
     * @return
     * @throws FormateoFechaException
     * @throws EyraDaoException
     */
    public List<Lectura> getLecturas(int id_tarificador, int hora, String periodo) throws FormateoFechaException, EyraDaoException {
        Periodo _periodo = new Periodo();
        _periodo.setFecha_final(periodo, Periodo.FORMATO_FECHA_AAAA_MM_DD);
        Session session = null;
        List<Lectura> _lista = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();
            _lista = session.createCriteria("Lectura_tm2")
                    .add(Restrictions.eq("periodo", _periodo.getFecha_inicial()))
                    .add(Restrictions.eq("hora", hora))
                    .add(Restrictions.eq("tarificador.id_tarificador", id_tarificador))
                    .addOrder(Order.asc("fecha"))
                    .addOrder(Order.desc("verano"))
                    .list();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return _lista;
    }

    public void setLectura(Lectura lectura) throws EyraDaoException {
        Session session = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();
            session.saveOrUpdate("Lectura_tm2", lectura);
            session.flush();
            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }
    }

    public double TotalSumaLecturas(int id_tarificador, Periodo periodo, boolean horarias) throws EyraDaoException {

        String tm = horarias ? "lecturas_tm1" : "lecturas_tm2";

        String sql = "SELECT SUM(activa_exportada + activa_importada + reactiva_q1 + reactiva_q2 + reactiva_q3 + reactiva_q4)  FROM " + tm
                + " WHERE id_tarificador=" + id_tarificador + " AND fecha between '"
                + periodo.getFechaFormateada(Periodo.FORMATO_FECHA_AAAA_MM_DD_HH_MM, Periodo.FECHA_INICIAL, Periodo.SEPARADOR_FECHA_GUION)
                + "' AND '" + periodo.getFechaFormateada(Periodo.FORMATO_FECHA_AAAA_MM_DD_HH_MM, Periodo.FECHA_FINAL, Periodo.SEPARADOR_FECHA_GUION)
                + "'";
        Session session = null;
        Object contador = 0;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            contador = session.createSQLQuery(sql).uniqueResult();
            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }
        return contador != null ? (Double) contador : 0;
    }

    /**
     * Listado de divisiones en las que están distribuidas las instalaciones a nivel del informes de Eyra
     * 
     * @return
     * @throws EyraDaoException
     */
    public List<Division> ListaDivisiones() throws EyraDaoException {
        Session session = null;
        List<Division> divisiones = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();

            divisiones = session.createCriteria(Division.class).addOrder(Order.asc("nombre")).list();

            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }

        return divisiones;
    }

    public void setLecturas(ArrayList<Lectura> lecturas, boolean horaria) throws EyraDaoException {
        Session session = null;
        String lectura = horaria ? "Lectura_tm1" : "Lectura_tm2";
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();
            for (Lectura _lectura : lecturas)
                session.saveOrUpdate(lectura, _lectura);
            session.flush();
            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }
    }

    public void BorrarLecturas(int id_tarificador, Periodo periodo, boolean horaria) throws EyraDaoException {
        Session session = null;
        String lectura = horaria ? "lecturas_tm1" : "lecturas_tm2";
        String sql = "DELETE FROM " + lectura + " WHERE id_tarificador=" + id_tarificador + " AND fecha BETWEEN '";
        sql += periodo.getFechaFormateada(Periodo.FORMATO_FECHA_AAAA_MM_DD_HH_MM, Periodo.FECHA_INICIAL, Periodo.SEPARADOR_FECHA_GUION);
        sql += "' AND '" + periodo.getFechaFormateada(Periodo.FORMATO_FECHA_AAAA_MM_DD_HH_MM, Periodo.FECHA_FINAL, Periodo.SEPARADOR_FECHA_GUION)
                + "'";
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction().begin();
            session.createSQLQuery(sql).executeUpdate();
            session.flush();
            session.beginTransaction().commit();
        } catch (HibernateException e) {
            if (session != null) session.beginTransaction().rollback();
            throw new EyraDaoException(e);
        } finally {
            if (session != null && session.isOpen()) session.close();
        }
    }
}
